/*
 * VisageManagerView.java
 */
package visagemanager;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

/**
 * The application's main frame.
 */
public class VisageManagerView extends FrameView {

    private static final double rotationStep = 2 * java.lang.Math.PI / 360;

    public VisageManagerView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
    }
    private FileNameExtensionFilter imageNameFilter = new FileNameExtensionFilter(
            "Images", "bmp", "jpg", "gif", "png", "jpeg");
    private JFileChooser openDialog = new JFileChooser();
    private Image currentImage = null;
    private File[] currentImageFiles = null;
    private int currentImageIndex = -1;
    private ArrayList<SampleInformation> currentSampleInformations;
    private int currentSampleIndex = -1;
    private File currentImageFile = null;
    private File currentMetaFile = null;
    private boolean newImage = false;
    private boolean fileOpened = false;//TODO: nécessaire? <==> (currentImage != null)
    private boolean userSaidNoFaces = false;
    private boolean fileSaved = true;
    private int creatingSample = -1;
    private int creatingSampleEventX;
    private int creatingSampleEventY;
    private int creatingSampleOriginX;
    private int creatingSampleOriginY;
    private boolean savingAll = false;
    private int savingAll_imageIndex;

    @SuppressWarnings("UseOfObsoleteCollectionType")
    public enum Facing {

        FULLLEFTPROFILE,
        HALFLEFTPROFILE,
        FRONT,
        HALFRIGHTPROFILE,
        FULLRIGHTPROFILE,
        NOTAFACE
    }

    public class SampleInformation {

        public SampleInformation(int _x, int _y, int _width, double _rotation, Facing _facing) {
            x = _x;
            y = _y;
            width = _width;
            rotation = _rotation;
            facing = _facing;
            updatePolygon();
        }

        private SampleInformation() {
        }
        public int x, y, width;
        public double rotation;
        public Facing facing;
        public Polygon surface;

        public final void updatePolygon() {
            Rectangle drawRect = ((ImageJPanel) imageDrawPanel).drawRect;
            if (currentImage.getHeight(null) != -1
                    &&drawRect != null) {
                AffineTransform trans = new AffineTransform();
                double zoomRatio = ((ImageJPanel) imageDrawPanel).zoomRatio;
                trans.translate(
                        drawRect.x + ((double) x + ((double) width / (double) 2)) / zoomRatio,
                        drawRect.y + ((double) y + ((double) width / (double) 2)) / zoomRatio);
                trans.rotate(rotation);
                trans.scale(
                        1 / zoomRatio,
                        1 / zoomRatio);
                trans.translate(-(x + (double)width / 2), -(y + (double)width / 2));
                Point2D UL = new Point2D.Double(x, y);
                Point2D UR = new Point2D.Double(x + width, y);
                Point2D LL = new Point2D.Double(x, y + width);
                Point2D LR = new Point2D.Double(x + width, y + width);
                Point2D ergot = new Point2D.Double(x+width,y-1);
                Point2D NewUL = new Point2D.Double(),
                        NewUR = new Point2D.Double(),
                        NewLL = new Point2D.Double(),
                        NewLR = new Point2D.Double();
                Point2D Newergot = new Point2D.Double();
                trans.transform(UL, NewUL);
                trans.transform(UR, NewUR);
                trans.transform(LL, NewLL);
                trans.transform(LR, NewLR);
                trans.transform(ergot,Newergot);
                surface = new Polygon();
                surface.addPoint((int) NewUL.getX(), (int) NewUL.getY());
                surface.addPoint((int) NewUR.getX(), (int) NewUR.getY());
                surface.addPoint((int) NewLR.getX(), (int) NewLR.getY());
                surface.addPoint((int) NewLL.getX(), (int) NewLL.getY());
                surface.addPoint((int) NewUL.getX(), (int) NewUL.getY());
                surface.addPoint((int) Newergot.getX(), (int) Newergot.getY());
            }
        }

        private int maxRGB(BufferedImage i,int blankRGB){
            int result=blankRGB;
            for(int j = 0; j <= 23 ; j++)
                for(int k = 0 ; k <= 23 ; k++)
                    if(i.getRGB(j,k)!=blankRGB)
                        result = i.getRGB(j,k);
            return result;
        }

        public Facing opposite(Facing f){
            switch(f){
                case FRONT: return Facing.FRONT;
                case HALFLEFTPROFILE: return Facing.HALFRIGHTPROFILE;
                case HALFRIGHTPROFILE: return Facing.HALFLEFTPROFILE;
                case FULLLEFTPROFILE: return Facing.FULLRIGHTPROFILE;
                case FULLRIGHTPROFILE: return Facing.FULLLEFTPROFILE;
                case NOTAFACE: return Facing.NOTAFACE;
                default:return Facing.NOTAFACE;
            }
        }

        @SuppressWarnings("SleepWhileHoldingLock")
        public boolean save(int index) {
            String savePath = currentImageFile.getParent();
            String filename = currentImageFile.getPath().substring(
                    currentImageFile.getPath().lastIndexOf(File.separatorChar) + 1);
            String flippedFilename = filename
                    .substring(0, filename.lastIndexOf('.'))
                    .concat("F_" + index + "_" + (int) -(((rotation*180/java.lang.Math.PI)-360) % 360)+ ".png");
            filename = filename
                    .substring(0, filename.lastIndexOf('.'))
                    .concat("_" + index + "_" + (int) (rotation*180/java.lang.Math.PI)+ ".png");
            String flippedSavePath = savePath.concat("" + File.separatorChar + opposite(facing).toString().toLowerCase() + File.separatorChar);
            savePath = savePath.concat("" + File.separatorChar + facing.toString().toLowerCase() + File.separatorChar);
            File saveFile = new File(savePath.concat(filename));
            File flippedSaveFile = new File(flippedSavePath.concat(flippedFilename));
            while(currentImage.getHeight(null)<=0){
                try {Thread.sleep(256);} catch (InterruptedException ex) {}
            }
            try {
                saveFile.getParentFile().mkdir();
                saveFile.createNewFile();
                flippedSaveFile.getParentFile().mkdir();
                flippedSaveFile.createNewFile();
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(mainPanel.getParent(),
                        "An error was encountered while saving file \"" + savePath + filename + "\". Check your permissions or free space, or try again.",
                        "Error",
                        JOptionPane.ERROR_MESSAGE);

                Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
                return false;
            }
            BufferedImage thisSampleImage = new BufferedImage(
                    24, 24, BufferedImage.TYPE_INT_RGB);
            BufferedImage thisFlippedSampleImage = new BufferedImage(
                    24,24,BufferedImage.TYPE_INT_RGB);
            int blankRGB = thisSampleImage.getRGB(0, 0);
            Graphics2D g = thisSampleImage.createGraphics();
            Graphics2D fg = thisFlippedSampleImage.createGraphics();
            while (currentImage.getHeight(null) == -1 || currentImage.getWidth(null) == -1) {
                try {
                    Thread.sleep(256);
                } catch (InterruptedException e) {
                }
            }
            do {
                g.drawImage(currentImage, 0, 0, 24, 24, x, y, x + width, y + width, null);
                fg.drawImage(currentImage, 24, 0, 0, 24, x, y, x + width, y + width, null);
            } while (maxRGB(thisSampleImage, blankRGB) == blankRGB&&maxRGB(thisFlippedSampleImage, blankRGB)==blankRGB);
            
            safeWriteImage(thisSampleImage, saveFile, thisFlippedSampleImage, flippedSaveFile, savePath, filename);

            return true;
        }

        private void safeWriteImage(BufferedImage thisSampleImage, File saveFile, BufferedImage thisFlippedSampleImage, File flippedSaveFile, String savePath, String filename) throws HeadlessException {
            try {
                ImageIO.write(thisSampleImage, "png", saveFile);
                ImageIO.write(thisFlippedSampleImage, "png", flippedSaveFile);
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(mainPanel.getParent(), "An error was encountered while saving file \"" + savePath + filename + "\". Check your permissions or free space, or try again.", "Error", JOptionPane.ERROR_MESSAGE);
                Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
                safeWriteImage(thisSampleImage,saveFile,thisFlippedSampleImage,flippedSaveFile,savePath,filename);
            }
        }

        public boolean save() {
            int index = 0;
            while (!this.equals(currentSampleInformations.get(index))) {
                index++;
            }
            return this.save(index);
        }
    }

    public void saveSampleInformation() {
        FileOutputStream metaFileStream;
        Element root = new Element("samples");
        root.setAttribute("image", currentImageFile.getName());
        if (!userSaidNoFaces) {
            root.setAttribute("containsFaces", "yes");
            for (int i = currentSampleInformations.size() - 1; i >= 0; i--) {
                Element thisSample = new Element("sample" + i);
                thisSample.setAttribute("x", "" + currentSampleInformations.get(i).x);
                thisSample.setAttribute("y", "" + currentSampleInformations.get(i).y);
                thisSample.setAttribute("width", "" + currentSampleInformations.get(i).width);
                thisSample.setAttribute("rotation", "" + currentSampleInformations.get(i).rotation);
                thisSample.setAttribute("facing", "" + currentSampleInformations.get(i).facing);
                root.addContent(thisSample);
                currentSampleInformations.get(i).save(i);
            }
        } else {
            root.setAttribute("containsFaces", "no");

            int minWidthHeight=currentImage.getHeight(null)>currentImage.getWidth(null)?
                        currentImage.getWidth(null):currentImage.getHeight(null);
            while(minWidthHeight<=0){
                try {Thread.sleep(256);} catch (InterruptedException ex) {}
                minWidthHeight =
                    currentImage.getHeight(null)>currentImage.getWidth(null)?
                        currentImage.getWidth(null):currentImage.getHeight(null);
            }
            int width = currentImage.getWidth(null);
            int height = currentImage.getHeight(null);
            int area = width * height;
            {
                int index=1;
                double probability;
                Random rn = new Random();
                SampleInformation thisSampleInformation;
                for (int size = 24; size <= minWidthHeight; size *= 1.25) {
                    if (size != minWidthHeight) {
                        probability = 1.5 * area / (48.0 * 48.0) / (width - size) / (height - size);
                    } else {
                        if (width < height) {
                            probability = 1.5 * area / (48.0 * 48.0) / (height - size);
                        } else {
                            probability = 1.5 * area / (48.0 * 48.0) / (width - size);
                        }
                    }
                    for (int row = 0; row + size < height; row += Math.ceil(size / 48.0)) {
                        for (int col = 0; col + size < width; col += Math.ceil(size / 48.0)) {
                            if (rn.nextDouble() < probability) {
                                thisSampleInformation = new SampleInformation(col, row, size, 0.0, Facing.NOTAFACE);
                                thisSampleInformation.save(index++);
                            }
                        }
                    }
                }
            }
        }
        Document xmlSave = new Document(root);
        XMLOutputter xmlSaver = new XMLOutputter();
        try {
            metaFileStream = new FileOutputStream(currentMetaFile);
            xmlSaver.output(xmlSave, metaFileStream);
        } catch (FileNotFoundException ex) {/*WTF??*/
            Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(mainPanel.getParent(),
                    "An error was encountered while saving the xml file. Check your free space or your permissions.",
                    "Error",
                    JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
        }
        fileSaved = true;
    }

    private boolean loadSampleInformation() {

        if (currentMetaFile.exists()) {
            SAXBuilder loader = new SAXBuilder();
            Document xmlSave;
            try {
                xmlSave = loader.build(new FileInputStream(currentMetaFile));
            } catch (JDOMException ex) {
                JOptionPane.showMessageDialog(mainPanel.getParent(),
                        "An error was encountered while loading the xml file. It seems corrupt.",
                        "Error",
                        JOptionPane.ERROR_MESSAGE);
                Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
                userSaidNoFaces = false;
                this.noFaceAtAllButton.setSelected(false);
                return false;
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(mainPanel.getParent(),
                        "A low-level error was encountered while loading the xml file. Check your permissions.",
                        "Error",
                        JOptionPane.ERROR_MESSAGE);
                Logger.getLogger(VisageManagerView.class.getName()).log(Level.SEVERE, null, ex);
                userSaidNoFaces = false;
                this.noFaceAtAllButton.setSelected(false);
                return false;
            }
            Element root = xmlSave.getRootElement();
            if (root.getAttribute("containsFaces") != null && root.getAttributeValue("containsFaces").equals("no")) {
                userSaidNoFaces = true;
                currentSampleInformations =  new ArrayList<SampleInformation>();
                this.noFaceAtAllButton.setSelected(true);
            } else {
                userSaidNoFaces = false;
                this.noFaceAtAllButton.setSelected(false);
                currentSampleInformations = new ArrayList<SampleInformation>();
                for (int i = root.getContentSize() - 1; i >= 0; i--) {
                    Element c = (Element) root.getContent(i);
                    SampleInformation r = new SampleInformation(
                            Integer.parseInt(c.getAttributeValue("x")),
                            Integer.parseInt(c.getAttributeValue("y")),
                            Integer.parseInt(c.getAttributeValue("width")),
                            Double.parseDouble(c.getAttributeValue("rotation")),
                            Facing.valueOf(c.getAttributeValue("facing")));
                    currentSampleInformations.add(r);
                }
                deselectSample();
            }
            return true;
        }
        currentSampleInformations = new ArrayList<SampleInformation>();
        userSaidNoFaces = false;
        this.noFaceAtAllButton.setSelected(false);
        return false;
    }

    public class ImageJPanel extends javax.swing.JPanel {

        double ratio;
        private int x;
        private int y;
        private int width;
        private int height;
        public Rectangle drawRect;
        public double zoomRatio;

        @Override
        public void paint(java.awt.Graphics g) {
            super.paint(g);
            if (fileOpened && currentImage.getHeight(this) != -1) {
                java.awt.Graphics2D g2 = (java.awt.Graphics2D) g;
                if (newImage) {
                    ratio =
                            ((double) currentImage.getHeight(this))
                            / ((double) currentImage.getWidth(this));
                    newImage = false;
                }
                double panelRatio = (double) (this.getHeight()
                        - this.getInsets().top
                        - this.getInsets().bottom)
                        / (double) (this.getWidth()
                        - this.getInsets().left
                        - this.getInsets().right);
                if (ratio > panelRatio) {
                    y = this.getInsets().top;
                    height = this.getHeight()
                            - this.getInsets().top
                            - this.getInsets().bottom;
                    zoomRatio = ((double) currentImage.getHeight(this)) / (double) height;
                    width = (int) (height
                            / ratio);
                    x = this.getInsets().left
                            + (int) ((this.getWidth() - width) / 2);
                } else {
                    x = this.getInsets().left;
                    width = this.getWidth()
                            - this.getInsets().left
                            - this.getInsets().right;
                    zoomRatio = ((double) currentImage.getWidth(this)) / (double) width;
                    height = (int) (width
                            * ratio);
                    y = this.getInsets().top
                            + (int) ((this.getHeight() - height) / 2);
                }
                drawRect = new Rectangle(x, y, width, height);
                g2.drawImage(currentImage,
                        x,
                        y,
                        x + width,
                        y + height,
                        0, 0,
                        currentImage.getWidth(this), currentImage.getHeight(this),
                        this);
                if(currentSampleInformations!=null)
                    for (int i = 0; i < currentSampleInformations.size(); i++) {
                        SampleInformation c = currentSampleInformations.get(i);
                        c.updatePolygon();
                        if (c.facing != Facing.NOTAFACE) {
                            g2.setColor(new Color(0, 255, 0));
                        } else {
                            g2.setColor(new Color(255, 0, 0));
                        }
                        if (c.surface != null) {
                            g2.drawPolygon(c.surface);
                        }
                    }
            }
            //g2.finalize();
        }
    }

    public class SampleJPanel extends javax.swing.JPanel {

        @Override
        public void paint(java.awt.Graphics g) {
            super.paint(g);
            if (currentSampleIndex > -1 && currentImage.getHeight(null) != -1) {
                Graphics2D g2 = (Graphics2D) g;
                BufferedImage rotatedImage = new BufferedImage(
                        currentImage.getWidth(null),
                        currentImage.getHeight(null),
                        BufferedImage.TYPE_INT_RGB);
                Graphics2D rotatedImageG = (Graphics2D) rotatedImage.getGraphics();
                AffineTransform originalTransf = rotatedImageG.getTransform();
                rotatedImageG.translate(
                        currentSampleInformations.get(currentSampleIndex).x
                        +(double)currentSampleInformations.get(currentSampleIndex).width/2,
                        currentSampleInformations.get(currentSampleIndex).y
                        +(double)currentSampleInformations.get(currentSampleIndex).width/2);
                rotatedImageG.rotate(-currentSampleInformations.get(currentSampleIndex).rotation);
                rotatedImageG.translate(
                        -currentSampleInformations.get(currentSampleIndex).x
                        -(double)currentSampleInformations.get(currentSampleIndex).width/2,
                        -currentSampleInformations.get(currentSampleIndex).y
                        -(double)currentSampleInformations.get(currentSampleIndex).width/2);
                rotatedImageG.drawImage(currentImage, 0, 0, null);
                g2.drawImage(rotatedImage,
                        this.getInsets().left,
                        this.getInsets().top,
                        this.getWidth() - this.getInsets().right,
                        this.getHeight() - this.getInsets().bottom,
                        currentSampleInformations.get(currentSampleIndex).x,
                        currentSampleInformations.get(currentSampleIndex).y,
                        currentSampleInformations.get(currentSampleIndex).x
                        + currentSampleInformations.get(currentSampleIndex).width,
                        currentSampleInformations.get(currentSampleIndex).y
                        + currentSampleInformations.get(currentSampleIndex).width,
                        null);
            }
        }
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = VisageManagerApp.getApplication().getMainFrame();
            aboutBox = new VisageManagerAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        VisageManagerApp.getApplication().show(aboutBox);
    }
    private final javax.swing.ButtonGroup faces = new javax.swing.ButtonGroup();

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        mainPanel = new javax.swing.JPanel();
        samplePanel = new javax.swing.JPanel();
        sampleDrawPanel = new SampleJPanel();
        notAFaceTButton = new javax.swing.JToggleButton();
        jSeparator2 = new javax.swing.JSeparator();
        FLjTButton = new javax.swing.JToggleButton();
        HLjTButton = new javax.swing.JToggleButton();
        FjTButton = new javax.swing.JToggleButton();
        HRjTButton = new javax.swing.JToggleButton();
        FRjTButton = new javax.swing.JToggleButton();
        sampleRotationPanel = new javax.swing.JPanel();
        rotationSlider = new javax.swing.JSlider();
        rotationLabel = new javax.swing.JLabel();
        rotateLeftButton = new javax.swing.JButton();
        rotateRightButton = new javax.swing.JButton();
        paddingLabel1 = new javax.swing.JLabel();
        paddingLabel2 = new javax.swing.JLabel();
        noFaceAtAllButton = new javax.swing.JToggleButton();
        imagePanel = new javax.swing.JPanel();
        imageDrawPanel = new ImageJPanel();
        imageSelectPanel = new javax.swing.JPanel();
        lowerPaddingLabel1 = new javax.swing.JLabel();
        severalPreviousImageButton = new javax.swing.JButton();
        previousImageButton = new javax.swing.JButton();
        saveImageButton = new javax.swing.JButton();
        nextImageButton = new javax.swing.JButton();
        lowerPaddingLabel2 = new javax.swing.JLabel();
        severalNextImageButton = new javax.swing.JButton();
        carryOnSampleInformationCheckBox = new javax.swing.JCheckBox();
        nPanel = new javax.swing.JPanel();
        multiplierSpinnerLabel = new javax.swing.JLabel();
        multiplierSpinner = new javax.swing.JSpinner(new SpinnerNumberModel(1,1,256,1));
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        openMenuItem = new javax.swing.JMenuItem();
        openNextMenuItem = new javax.swing.JMenuItem();
        saveMenuItem = new javax.swing.JMenuItem();
        saveAllMenuItem = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setPreferredSize(new java.awt.Dimension(640, 480));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${component.focusable}"), mainPanel, org.jdesktop.beansbinding.BeanProperty.create("focusable"));
        bindingGroup.addBinding(binding);

        mainPanel.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                mainPanelKeyPressed(evt);
            }
        });
        mainPanel.setLayout(new java.awt.GridBagLayout());

        samplePanel.setFocusable(false);
        samplePanel.setMinimumSize(new java.awt.Dimension(600, 169));
        samplePanel.setName("samplePanel"); // NOI18N
        samplePanel.setPreferredSize(new java.awt.Dimension(600, 169));
        samplePanel.setRequestFocusEnabled(false);
        samplePanel.setLayout(new java.awt.GridBagLayout());

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(visagemanager.VisageManagerApp.class).getContext().getResourceMap(VisageManagerView.class);
        sampleDrawPanel.setBackground(resourceMap.getColor("sampleDrawPanel.background")); // NOI18N
        sampleDrawPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder(javax.swing.border.EtchedBorder.RAISED, resourceMap.getColor("sampleDrawPanel.border.highlightColor"), resourceMap.getColor("sampleDrawPanel.border.shadowColor"))); // NOI18N
        sampleDrawPanel.setFocusable(false);
        sampleDrawPanel.setMaximumSize(new java.awt.Dimension(100, 100));
        sampleDrawPanel.setMinimumSize(new java.awt.Dimension(100, 100));
        sampleDrawPanel.setName("sampleDrawPanel"); // NOI18N
        sampleDrawPanel.setPreferredSize(new java.awt.Dimension(100, 100));

        javax.swing.GroupLayout sampleDrawPanelLayout = new javax.swing.GroupLayout(sampleDrawPanel);
        sampleDrawPanel.setLayout(sampleDrawPanelLayout);
        sampleDrawPanelLayout.setHorizontalGroup(
            sampleDrawPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 96, Short.MAX_VALUE)
        );
        sampleDrawPanelLayout.setVerticalGroup(
            sampleDrawPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 96, Short.MAX_VALUE)
        );

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.weightx = 1.0;
        samplePanel.add(sampleDrawPanel, gridBagConstraints);

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(visagemanager.VisageManagerApp.class).getContext().getActionMap(VisageManagerView.class, this);
        notAFaceTButton.setAction(actionMap.get("notAFaceSelected")); // NOI18N
        faces.add(notAFaceTButton);
        notAFaceTButton.setText(resourceMap.getString("notAFaceTButton.text")); // NOI18N
        notAFaceTButton.setFocusable(false);
        notAFaceTButton.setName("notAFaceTButton"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(notAFaceTButton, gridBagConstraints);

        jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
        jSeparator2.setMaximumSize(new java.awt.Dimension(32767, 23));
        jSeparator2.setMinimumSize(new java.awt.Dimension(2, 23));
        jSeparator2.setName("jSeparator2"); // NOI18N
        jSeparator2.setOpaque(true);
        jSeparator2.setPreferredSize(new java.awt.Dimension(2, 23));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 4);
        samplePanel.add(jSeparator2, gridBagConstraints);

        FLjTButton.setAction(actionMap.get("fullLeftFacingSelected")); // NOI18N
        faces.add(FLjTButton);
        FLjTButton.setText(resourceMap.getString("UFLProfile.text")); // NOI18N
        FLjTButton.setFocusable(false);
        FLjTButton.setName("UFLProfile"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(FLjTButton, gridBagConstraints);

        HLjTButton.setAction(actionMap.get("halfLeftFacingSelected")); // NOI18N
        faces.add(HLjTButton);
        HLjTButton.setText(resourceMap.getString("UHLProfile.text")); // NOI18N
        HLjTButton.setFocusable(false);
        HLjTButton.setName("UHLProfile"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(HLjTButton, gridBagConstraints);

        FjTButton.setAction(actionMap.get("frontFacingSelected")); // NOI18N
        faces.add(FjTButton);
        FjTButton.setText(resourceMap.getString("UFront.text")); // NOI18N
        FjTButton.setFocusable(false);
        FjTButton.setName("UFront"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(FjTButton, gridBagConstraints);

        HRjTButton.setAction(actionMap.get("halfRightFacingSelected")); // NOI18N
        faces.add(HRjTButton);
        HRjTButton.setText(resourceMap.getString("UHRProfile.text")); // NOI18N
        HRjTButton.setFocusable(false);
        HRjTButton.setName("UHRProfile"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(HRjTButton, gridBagConstraints);

        FRjTButton.setAction(actionMap.get("fullRightFacingSelected")); // NOI18N
        faces.add(FRjTButton);
        FRjTButton.setText(resourceMap.getString("UFRProfile.text")); // NOI18N
        FRjTButton.setFocusable(false);
        FRjTButton.setName("UFRProfile"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        samplePanel.add(FRjTButton, gridBagConstraints);

        sampleRotationPanel.setFocusable(false);
        sampleRotationPanel.setMinimumSize(new java.awt.Dimension(500, 108));
        sampleRotationPanel.setName("sampleRotationPanel"); // NOI18N
        sampleRotationPanel.setPreferredSize(new java.awt.Dimension(360, 88));
        sampleRotationPanel.setLayout(new java.awt.GridBagLayout());

        rotationSlider.setMajorTickSpacing(90);
        rotationSlider.setMaximum(360);
        rotationSlider.setMinorTickSpacing(30);
        rotationSlider.setPaintLabels(true);
        rotationSlider.setPaintTicks(true);
        rotationSlider.setPaintTrack(false);
        rotationSlider.setValue(0);
        rotationSlider.setFocusable(false);
        rotationSlider.setMaximumSize(new java.awt.Dimension(360, 65));
        rotationSlider.setMinimumSize(new java.awt.Dimension(360, 65));
        rotationSlider.setName("rotationSlider"); // NOI18N
        rotationSlider.setPreferredSize(new java.awt.Dimension(360, 65));
        rotationSlider.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                rotationSliderStateChanged(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 4;
        sampleRotationPanel.add(rotationSlider, gridBagConstraints);

        rotationLabel.setLabelFor(rotationSlider);
        rotationLabel.setText(resourceMap.getString("rotationLabel.text")); // NOI18N
        rotationLabel.setAlignmentX(0.5F);
        rotationLabel.setFocusable(false);
        rotationLabel.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        rotationLabel.setMaximumSize(new java.awt.Dimension(100, 14));
        rotationLabel.setMinimumSize(new java.awt.Dimension(100, 14));
        rotationLabel.setName("rotationLabel"); // NOI18N
        rotationLabel.setPreferredSize(new java.awt.Dimension(100, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        sampleRotationPanel.add(rotationLabel, gridBagConstraints);

        rotateLeftButton.setAction(actionMap.get("rotateLeftAction")); // NOI18N
        rotateLeftButton.setText(resourceMap.getString("rotateLeftButton.text")); // NOI18N
        rotateLeftButton.setFocusable(false);
        rotateLeftButton.setName("rotateLeftButton"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        sampleRotationPanel.add(rotateLeftButton, gridBagConstraints);

        rotateRightButton.setAction(actionMap.get("rotateRightAction")); // NOI18N
        rotateRightButton.setText(resourceMap.getString("rotateRightButton.text")); // NOI18N
        rotateRightButton.setFocusable(false);
        rotateRightButton.setName("rotateRightButton"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        sampleRotationPanel.add(rotateRightButton, gridBagConstraints);

        paddingLabel1.setText(resourceMap.getString("paddingLabel1.text")); // NOI18N
        paddingLabel1.setFocusable(false);
        paddingLabel1.setName("paddingLabel1"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 0.5;
        sampleRotationPanel.add(paddingLabel1, gridBagConstraints);

        paddingLabel2.setText(resourceMap.getString("paddingLabel2.text")); // NOI18N
        paddingLabel2.setFocusable(false);
        paddingLabel2.setName("paddingLabel2"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 0.5;
        sampleRotationPanel.add(paddingLabel2, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 8;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        samplePanel.add(sampleRotationPanel, gridBagConstraints);

        noFaceAtAllButton.setAction(actionMap.get("NoFaceAtAllSelected")); // NOI18N
        noFaceAtAllButton.setText(resourceMap.getString("noFaceAtAllButton.text")); // NOI18N
        noFaceAtAllButton.setFocusable(false);
        noFaceAtAllButton.setName("noFaceAtAllButton"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        samplePanel.add(noFaceAtAllButton, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        mainPanel.add(samplePanel, gridBagConstraints);

        imagePanel.setFocusable(false);
        imagePanel.setMinimumSize(new java.awt.Dimension(320, 45));
        imagePanel.setName("imagePanel"); // NOI18N
        imagePanel.setPreferredSize(new java.awt.Dimension(340, 45));
        imagePanel.setLayout(new java.awt.GridBagLayout());

        imageDrawPanel.setBackground(resourceMap.getColor("imageDrawPanel.background")); // NOI18N
        imageDrawPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder(resourceMap.getColor("imageDrawPanel.border.highlightColor"), resourceMap.getColor("imageDrawPanel.border.shadowColor"))); // NOI18N
        imageDrawPanel.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        imageDrawPanel.setName("imageDrawPanel"); // NOI18N
        imageDrawPanel.setPreferredSize(new java.awt.Dimension(240, 240));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${component.focusable}"), imageDrawPanel, org.jdesktop.beansbinding.BeanProperty.create("focusable"));
        bindingGroup.addBinding(binding);

        imageDrawPanel.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                imageDrawPanelMouseWheelMoved(evt);
            }
        });
        imageDrawPanel.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                imageDrawPanelMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                imageDrawPanelMouseReleased(evt);
            }
        });
        imageDrawPanel.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                imageDrawPanelMouseDragged(evt);
            }
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                imageDrawPanelMouseMoved(evt);
            }
        });

        javax.swing.GroupLayout imageDrawPanelLayout = new javax.swing.GroupLayout(imageDrawPanel);
        imageDrawPanel.setLayout(imageDrawPanelLayout);
        imageDrawPanelLayout.setHorizontalGroup(
            imageDrawPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 643, Short.MAX_VALUE)
        );
        imageDrawPanelLayout.setVerticalGroup(
            imageDrawPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 130, Short.MAX_VALUE)
        );

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.ipadx = 100;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
        gridBagConstraints.weightx = 0.5;
        gridBagConstraints.weighty = 0.5;
        imagePanel.add(imageDrawPanel, gridBagConstraints);

        imageSelectPanel.setFocusable(false);
        imageSelectPanel.setName("imageSelectPanel"); // NOI18N
        imageSelectPanel.setPreferredSize(new java.awt.Dimension(317, 82));
        imageSelectPanel.setLayout(new java.awt.GridBagLayout());

        lowerPaddingLabel1.setText(resourceMap.getString("lowerPaddingLabel1.text")); // NOI18N
        lowerPaddingLabel1.setName("lowerPaddingLabel1"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.weightx = 0.1;
        imageSelectPanel.add(lowerPaddingLabel1, gridBagConstraints);

        severalPreviousImageButton.setAction(actionMap.get("severalPreviousOpenAction")); // NOI18N
        severalPreviousImageButton.setText(resourceMap.getString("severalPreviousImageButton.text")); // NOI18N
        severalPreviousImageButton.setFocusable(false);
        severalPreviousImageButton.setName("severalPreviousImageButton"); // NOI18N
        previousImageButton.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        imageSelectPanel.add(severalPreviousImageButton, gridBagConstraints);

        previousImageButton.setAction(actionMap.get("openPreviousImageAction")); // NOI18N
        previousImageButton.setText(resourceMap.getString("previousImageButton.text")); // NOI18N
        previousImageButton.setFocusable(false);
        previousImageButton.setName("previousImageButton"); // NOI18N
        previousImageButton.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        imageSelectPanel.add(previousImageButton, gridBagConstraints);

        saveImageButton.setAction(actionMap.get("saveAction")); // NOI18N
        saveImageButton.setIcon(resourceMap.getIcon("saveImageButton.icon")); // NOI18N
        saveImageButton.setText(resourceMap.getString("saveImageButton.text")); // NOI18N
        saveImageButton.setFocusable(false);
        saveImageButton.setName("saveImageButton"); // NOI18N
        saveImageButton.setPreferredSize(new java.awt.Dimension(90, 24));
        saveImageButton.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        imageSelectPanel.add(saveImageButton, gridBagConstraints);

        nextImageButton.setAction(actionMap.get("openNextImageAction")); // NOI18N
        nextImageButton.setText(resourceMap.getString("nextImageButton.text")); // NOI18N
        nextImageButton.setAlignmentX(0.5F);
        nextImageButton.setAlignmentY(1.0F);
        nextImageButton.setFocusable(false);
        nextImageButton.setName("nextImageButton"); // NOI18N
        nextImageButton.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 1;
        imageSelectPanel.add(nextImageButton, gridBagConstraints);

        lowerPaddingLabel2.setName("lowerPaddingLabel2"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 6;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.weightx = 0.1;
        imageSelectPanel.add(lowerPaddingLabel2, gridBagConstraints);

        severalNextImageButton.setAction(actionMap.get("severalNextOpenAction")); // NOI18N
        severalNextImageButton.setText(resourceMap.getString("severalNextImageButton.text")); // NOI18N
        severalNextImageButton.setAlignmentX(0.5F);
        severalNextImageButton.setAlignmentY(1.0F);
        severalNextImageButton.setFocusable(false);
        severalNextImageButton.setName("severalNextImageButton"); // NOI18N
        nextImageButton.setEnabled(false);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 1;
        imageSelectPanel.add(severalNextImageButton, gridBagConstraints);

        carryOnSampleInformationCheckBox.setActionCommand(resourceMap.getString("carryOnSampleInformationCheckBox.actionCommand")); // NOI18N
        carryOnSampleInformationCheckBox.setFocusable(false);
        carryOnSampleInformationCheckBox.setLabel(resourceMap.getString("carryOnSampleInformationCheckBox.label")); // NOI18N
        carryOnSampleInformationCheckBox.setName("carryOnSampleInformationCheckBox"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 7;
        imageSelectPanel.add(carryOnSampleInformationCheckBox, gridBagConstraints);

        nPanel.setFocusable(false);
        nPanel.setName("nPanel"); // NOI18N

        multiplierSpinnerLabel.setText(resourceMap.getString("multiplierSpinnerLabel.text")); // NOI18N
        multiplierSpinnerLabel.setFocusable(false);
        multiplierSpinnerLabel.setName("multiplierSpinnerLabel"); // NOI18N
        nPanel.add(multiplierSpinnerLabel);

        multiplierSpinner.setFocusable(false);
        multiplierSpinner.setName("multiplierSpinner"); // NOI18N
        multiplierSpinner.setValue(1);
        nPanel.add(multiplierSpinner);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 7;
        imageSelectPanel.add(nPanel, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
        imagePanel.add(imageSelectPanel, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 0.5;
        gridBagConstraints.weighty = 0.5;
        mainPanel.add(imagePanel, gridBagConstraints);

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        openMenuItem.setAction(actionMap.get("openAction")); // NOI18N
        openMenuItem.setText(resourceMap.getString("openMenuItem.text")); // NOI18N
        openMenuItem.setName("openMenuItem"); // NOI18N
        fileMenu.add(openMenuItem);

        openNextMenuItem.setAction(actionMap.get("openNextImageAction")); // NOI18N
        openNextMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_D, java.awt.event.InputEvent.CTRL_MASK));
        openNextMenuItem.setLabel(resourceMap.getString("openNextMenuItem.label")); // NOI18N
        openNextMenuItem.setName("openNextMenuItem"); // NOI18N
        fileMenu.add(openNextMenuItem);

        saveMenuItem.setAction(actionMap.get("saveAction")); // NOI18N
        saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveMenuItem.setText(resourceMap.getString("saveMenuItem.text")); // NOI18N
        saveMenuItem.setName("saveMenuItem"); // NOI18N
        saveMenuItem.setEnabled(false);
        fileMenu.add(saveMenuItem);

        saveAllMenuItem.setAction(actionMap.get("saveAllAction")); // NOI18N
        saveAllMenuItem.setText(resourceMap.getString("saveAllMenuItem.text")); // NOI18N
        saveAllMenuItem.setName("saveAllMenuItem"); // NOI18N
        saveAllMenuItem.setEnabled(false);
        fileMenu.add(saveAllMenuItem);

        jSeparator1.setName("jSeparator1"); // NOI18N
        fileMenu.add(jSeparator1);

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setFocusable(false);
        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setFocusable(false);
        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setFocusable(false);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setFocusable(false);
        progressBar.setMinimumSize(new java.awt.Dimension(100, 20));
        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 657, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 487, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 146, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);

        bindingGroup.bind();
    }// </editor-fold>//GEN-END:initComponents

    private void imageDrawPanelMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageDrawPanelMouseMoved

        if (fileOpened && ((ImageJPanel) imageDrawPanel).drawRect != null) {
            Rectangle rect = ((ImageJPanel) imageDrawPanel).drawRect;
            if(currentSampleInformations!=null)
            if (rect.contains(evt.getPoint()) && currentImage.getHeight(null) != -1) {
                int focusedSampleIndex = -1;

                for (int i = 0; i < currentSampleInformations.size(); i++) {
                    currentSampleInformations.get(i).updatePolygon();
                    if (!currentSampleInformations.get(i).surface.contains(evt.getPoint())) {
                        continue;
                    }
                    if (i == currentSampleIndex) {
                        imageDrawPanel.setCursor(new Cursor(Cursor.MOVE_CURSOR));
                        return;
                    }
                    focusedSampleIndex = i;
                }
                if (focusedSampleIndex > -1) {
                    sampleDrawPanel.setVisible(false);
                    currentSampleIndex = focusedSampleIndex;
                    switch(currentSampleInformations.get(currentSampleIndex).facing){
                        case FRONT:
                            FjTButton.setSelected(true);
                            break;
                        case FULLLEFTPROFILE:
                            FLjTButton.setSelected(true);
                            break;
                        case FULLRIGHTPROFILE:
                            FRjTButton.setSelected(true);
                            break;
                        case HALFLEFTPROFILE:
                            HLjTButton.setSelected(true);
                            break;
                        case HALFRIGHTPROFILE:
                            HRjTButton.setSelected(true);
                            break;
                        case NOTAFACE:
                            notAFaceTButton.setSelected(true);
                    }
                    sampleSelected();
                    sampleDrawPanel.setVisible(true);
                }
                imageDrawPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }
}//GEN-LAST:event_imageDrawPanelMouseMoved

    private void processMouseSampleCreate(java.awt.event.MouseEvent evt){
        Rectangle rect = ((ImageJPanel) imageDrawPanel).drawRect;
            if (rect.contains(evt.getPoint())) {
                double zoomRatio = ((ImageJPanel) imageDrawPanel).zoomRatio;
                int resizedX = (int) ((evt.getX() - rect.x) * zoomRatio);
                int resizedY = (int) ((evt.getY() - rect.y) * zoomRatio);
                int width = java.lang.Math.abs(
                        resizedX - creatingSampleOriginX);
                if (width < 24) width = 24;
                int height = java.lang.Math.abs(
                        resizedY - creatingSampleOriginY);
                if (height < 24) height = 24;
                width = java.lang.Math.max(width, height);
                if(evt.getX() > creatingSampleEventX) {
                    if(creatingSampleOriginX+width>currentImage.getWidth(null)) return;
                    if (evt.getY() > creatingSampleEventY) {
                        if(creatingSampleOriginY+width>currentImage.getHeight(null)) return;
                        currentSampleInformations.get(creatingSample).y = creatingSampleOriginY;
                    } else {
                        if(creatingSampleOriginY-width<0) return;
                        currentSampleInformations.get(creatingSample).y = creatingSampleOriginY-width;
                    }
                    currentSampleInformations.get(creatingSample).x = creatingSampleOriginX;
                } else {
                    if(creatingSampleOriginX-width<0) return;
                    if (evt.getY() > creatingSampleEventY) {
                        if(creatingSampleOriginY+width>currentImage.getHeight(null)) return;
                        currentSampleInformations.get(creatingSample).y = creatingSampleOriginY;
                    } else {
                        if(creatingSampleOriginY-width<0) return;
                        currentSampleInformations.get(creatingSample).y = creatingSampleOriginY-width;
                    }
                    currentSampleInformations.get(creatingSample).x = creatingSampleOriginX-width;
                }
                currentSampleInformations.get(creatingSample).width = width;
                currentSampleInformations.get(creatingSample).updatePolygon();
                imageDrawPanel.repaint();
                fileSaved = false;
            }
    }

    private void processMouseSampleMove(java.awt.event.MouseEvent evt){
        Rectangle rect = ((ImageJPanel) imageDrawPanel).drawRect;
        if (fileOpened && rect != null && rect.contains(evt.getPoint())) {
            if(currentSampleIndex >= 0){
                double zoomRatio = ((ImageJPanel) imageDrawPanel).zoomRatio;
                int resizedX = (int) ((evt.getX() - rect.x) * zoomRatio);
                int resizedY = (int) ((evt.getY() - rect.y) * zoomRatio);
                int newX = currentSampleInformations.get(currentSampleIndex).x
                        + resizedX - creatingSampleOriginX;
                int newY = currentSampleInformations.get(currentSampleIndex).y
                        + resizedY - creatingSampleOriginY;
                int width = currentSampleInformations.get(currentSampleIndex).width;
                if(newX < 0 || newX >= currentImage.getWidth(null)
                        ||newY < 0 || newY >= currentImage.getHeight(null)
                        ||newX + width < 0 || newX + width >= currentImage.getWidth(null)
                        ||newY + width < 0 || newY + width >= currentImage.getHeight(null))
                    return;
                currentSampleInformations.get(currentSampleIndex).x = newX;
                currentSampleInformations.get(currentSampleIndex).y = newY;
                creatingSampleOriginX = resizedX;
                creatingSampleOriginY = resizedY;
                sampleDrawPanel.repaint();
                imageDrawPanel.repaint();
                fileSaved = false;
            }
        }
    }

    private void imageDrawPanelMouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageDrawPanelMouseDragged
        if(currentImage.getHeight(null) >= 0){
            if (creatingSample >= 0 ) {
                processMouseSampleCreate(evt);
            } else {
                processMouseSampleMove(evt);
            }
        }
}//GEN-LAST:event_imageDrawPanelMouseDragged

    private void imageDrawPanelMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageDrawPanelMouseReleased
        if (creatingSample >= 0) {
            if(currentSampleInformations.get(creatingSample).width == 0){
                currentSampleInformations.remove(currentSampleInformations.get(creatingSample));
                creatingSample = -1;
                return;
            }
            currentSampleInformations.get(creatingSample).updatePolygon();
            creatingSample = -1;
        }
}//GEN-LAST:event_imageDrawPanelMouseReleased

    private void imageDrawPanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_imageDrawPanelMousePressed
        Rectangle rect = ((ImageJPanel) imageDrawPanel).drawRect;
        if (fileOpened && rect != null && rect.contains(evt.getPoint())) {
            double zoomRatio = ((ImageJPanel) imageDrawPanel).zoomRatio;
            int resizedX = (int) ((evt.getX() - rect.x) * zoomRatio);
            int resizedY = (int) ((evt.getY() - rect.y) * zoomRatio);
            creatingSampleEventX = evt.getX();
            creatingSampleEventY = evt.getY();
            creatingSampleOriginX = resizedX;
            creatingSampleOriginY = resizedY;
            if(currentSampleIndex >= 0
                    && currentSampleInformations
                    .get(currentSampleIndex)
                    .surface .contains(evt.getPoint())
              ) return;
            creatingSample = currentSampleInformations.size();
            currentSampleInformations.add(new SampleInformation(resizedX, resizedY, 0, 0, Facing.NOTAFACE));
        }
}//GEN-LAST:event_imageDrawPanelMousePressed

    private void mainPanelKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_mainPanelKeyPressed
        if(currentSampleIndex>=0&&(evt.getKeyCode()==java.awt.event.KeyEvent.VK_DELETE)){
            currentSampleInformations.remove(currentSampleInformations.get(currentSampleIndex));
            deselectSample();
        imageDrawPanel.repaint();
        sampleDrawPanel.repaint();
        }
    }//GEN-LAST:event_mainPanelKeyPressed

    private void imageDrawPanelMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_imageDrawPanelMouseWheelMoved
        if(currentSampleIndex >=0 && currentImage.getHeight(null) >= 0){
            
            int factor=1;
            if(evt.isControlDown()) factor = 10;
            int newWidth = currentSampleInformations.get(currentSampleIndex).width
                    - factor * evt.getWheelRotation();
            if(currentSampleInformations.get(currentSampleIndex).x+newWidth>currentImage.getWidth(null)
                    ||currentSampleInformations.get(currentSampleIndex).y+newWidth>currentImage.getHeight(null))
                return;
            if(newWidth < 24 ) newWidth = 24;
            currentSampleInformations.get(currentSampleIndex).width = newWidth;
            imageDrawPanel.repaint();
            sampleDrawPanel.repaint();
        }
    }//GEN-LAST:event_imageDrawPanelMouseWheelMoved

    private void rotationSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_rotationSliderStateChanged
        if(currentSampleIndex >= 0){
            currentSampleInformations.get(currentSampleIndex).rotation
                    =rotationSlider.getValue()*java.lang.Math.PI/180.0;
            rotationLabel.setText(
                    "Rotation : "
                    + (int) (currentSampleInformations.get(currentSampleIndex).rotation * 180 / java.lang.Math.PI)
                    +"°");
            sampleDrawPanel.repaint();
            imageDrawPanel.repaint();
        }
    }//GEN-LAST:event_rotationSliderStateChanged

    private void open(File image) {
        currentImageFile = image;
        currentImage = Toolkit.getDefaultToolkit().createImage(currentImageFile.getPath());
        {
            String metaPath = currentImageFile.getPath();
            int indexOfExtention = metaPath.lastIndexOf('.') + 1;
            metaPath = metaPath.substring(0, indexOfExtention);
            metaPath = metaPath.concat("xml");
            currentMetaFile = new File(metaPath);
            if (!loadSampleInformation()) {
                currentSampleInformations = new ArrayList<SampleInformation>();
            }
        }
        fileOpened = true;
        newImage = true;
        if (!savingAll) {
            severalPreviousImageButton.setEnabled(true);
            previousImageButton.setEnabled(true);
            saveImageButton.setEnabled(true);
            nextImageButton.setEnabled(true);
            severalNextImageButton.setEnabled(true);
            if (currentImageIndex <= Integer.parseInt(multiplierSpinner.getValue().toString())-1)
                severalPreviousImageButton.setEnabled(false);
            if (currentImageIndex <= 0)
                previousImageButton.setEnabled(false);
            if (currentImageIndex >= currentImageFiles.length - 1)
                nextImageButton.setEnabled(false);
            if (currentImageIndex >= currentImageFiles.length - Integer.parseInt(multiplierSpinner.getValue().toString()))
                severalNextImageButton.setEnabled(false);
        }
        deselectSample();
        this.getFrame().setTitle("Visage Manager : " + currentImageFile.getPath());
        this.getRootPane().repaint();
    }

    private void openKeepSample(File image) {
        currentImageFile = image;
        currentImage = Toolkit.getDefaultToolkit().createImage(currentImageFile.getPath());
        {
            String metaPath = currentImageFile.getPath();
            int indexOfExtention = metaPath.lastIndexOf('.') + 1;
            metaPath = metaPath.substring(0, indexOfExtention);
            metaPath = metaPath.concat("xml");
            currentMetaFile = new File(metaPath);
        }
        fileOpened = true;
        newImage = true;
        severalPreviousImageButton.setEnabled(true);
        previousImageButton.setEnabled(true);
        saveImageButton.setEnabled(true);
        nextImageButton.setEnabled(true);
        severalNextImageButton.setEnabled(true);
        if (currentImageIndex <= Integer.parseInt(multiplierSpinner.getValue().toString())-1)
            severalPreviousImageButton.setEnabled(false);
        if (currentImageIndex <= 0)
            previousImageButton.setEnabled(false);
        if (currentImageIndex >= currentImageFiles.length - 1)
            nextImageButton.setEnabled(false);
        if (currentImageIndex >= currentImageFiles.length - Integer.parseInt(multiplierSpinner.getValue().toString()))
            severalNextImageButton.setEnabled(false);
        this.getFrame().setTitle("Visage Manager : " + currentImageFile.getPath());
        this.getRootPane().repaint();
        saveSampleInformation();
    }

    private void updateDirectory(File selectedImage) {
        if (selectedImage != null) {
            if(currentImageFile != null && currentImageFile.getParent().equals(selectedImage.getParent()))
                return;
            class ImageExtFilter implements java.io.FileFilter {

                public boolean accept(File f) {
                    return f.getPath().toLowerCase().endsWith(".bmp")
                            || f.getPath().toLowerCase().endsWith(".png")
                            || f.getPath().toLowerCase().endsWith(".gif")
                            || f.getPath().toLowerCase().endsWith(".jpg")
                            || f.getPath().toLowerCase().endsWith(".jpeg");
                }
            }
            File directory = selectedImage.getParentFile();
            currentImageFiles = directory.listFiles(new ImageExtFilter());
            currentImageIndex = 0;
            while (currentImageIndex < currentImageFiles.length
                    && !currentImageFiles[currentImageIndex].equals(selectedImage)) {
                currentImageIndex++;
            }
            enableInterface();
        }
    }

    @Action
    public void openAction() {
        //TODO check if unsaved changes (fileSaved) and take action
        openDialog.setDialogType(JFileChooser.OPEN_DIALOG);
        openDialog.setFileFilter(imageNameFilter);
        openDialog.setSelectedFile(null);
        openDialog.showDialog(this.mainPanel.getParent(), "Manage");
        if (openDialog.getSelectedFile() == null)
            return;
        if (!openDialog.getSelectedFile().equals(currentImageFile)) {
            updateDirectory(openDialog.getSelectedFile());
            open(openDialog.getSelectedFile());
            imageDrawPanel.repaint();
            saveMenuItem.setEnabled(true);
            saveAllMenuItem.setEnabled(true);
        }
    }

    @Action
    public void openNextImageAction() {
        currentImageIndex++;
        if(carryOnSampleInformationCheckBox.isSelected())
            openKeepSample(currentImageFiles[currentImageIndex]);
        else
            open(currentImageFiles[currentImageIndex]);
    }

    @Action
    public void openPreviousImageAction() {
        currentImageIndex--;
        if(carryOnSampleInformationCheckBox.isSelected())
            openKeepSample(currentImageFiles[currentImageIndex]);
        else
            open(currentImageFiles[currentImageIndex]);
    }

    @Action
    public void saveAction() {
        saveSampleInformation();
    }

    @Action
    public void frontFacingSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.FRONT;
            this.getRootPane().repaint();
        }
    }

    @Action
    public void halfRightFacingSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.HALFRIGHTPROFILE;
            this.getRootPane().repaint();
        }
    }

    @Action
    public void halfLeftFacingSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.HALFLEFTPROFILE;
            this.getRootPane().repaint();
        }
    }

    @Action
    public void fullLeftFacingSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.FULLLEFTPROFILE;
            this.getRootPane().repaint();
        }
    }

    @Action
    public void fullRightFacingSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.FULLRIGHTPROFILE;
            this.getRootPane().repaint();
        }
    }

    public void disableInterface() {
        openMenuItem.setEnabled(false);
        saveMenuItem.setEnabled(false);
        saveAllMenuItem.setEnabled(false);
        notAFaceTButton.setEnabled(false);
        FLjTButton.setEnabled(false);
        HLjTButton.setEnabled(false);
        FjTButton.setEnabled(false);
        HRjTButton.setEnabled(false);
        FRjTButton.setEnabled(false);
        rotationSlider.setEnabled(false);
        rotateLeftButton.setEnabled(false);
        rotateRightButton.setEnabled(false);
        noFaceAtAllButton.setEnabled(false);
        severalPreviousImageButton.setEnabled(false);
        previousImageButton.setEnabled(false);
        nextImageButton.setEnabled(false);
        severalNextImageButton.setEnabled(false);
        carryOnSampleInformationCheckBox.setEnabled(false);
        multiplierSpinner.setEnabled(false);
    }
    public void enableInterface(){
        updateDirectory(currentImageFile);
        openMenuItem.setEnabled(true);
        saveMenuItem.setEnabled(true);
        saveAllMenuItem.setEnabled(true);
        notAFaceTButton.setEnabled(true);
        FLjTButton.setEnabled(true);
        HLjTButton.setEnabled(true);
        FjTButton.setEnabled(true);
        HRjTButton.setEnabled(true);
        FRjTButton.setEnabled(true);
        rotationSlider.setEnabled(true);
        rotateLeftButton.setEnabled(true);
        rotateRightButton.setEnabled(true);
        noFaceAtAllButton.setEnabled(true);
        if(currentImageIndex > Integer.parseInt(multiplierSpinner.getValue().toString()))
            severalPreviousImageButton.setEnabled(true);
        if(currentImageIndex > 0)
            previousImageButton.setEnabled(true);
        if(currentImageIndex < currentImageFiles.length -1)
            nextImageButton.setEnabled(true);
        if(currentImageIndex < currentImageFiles.length -Integer.parseInt(multiplierSpinner.getValue().toString()))
            severalNextImageButton.setEnabled(true);
        carryOnSampleInformationCheckBox.setEnabled(true);
        multiplierSpinner.setEnabled(true);
    }

    @Action
    public void notAFaceSelected() {
        if(currentSampleIndex>=0){
            currentSampleInformations.get(currentSampleIndex).facing=Facing.NOTAFACE;
            this.getRootPane().repaint();
        }
    }

    private void deselectSample(){
        currentSampleIndex = -1;
        rotateLeftButton.setEnabled(false);
        rotateRightButton.setEnabled(false);
        rotationLabel.setText("Rotation :");
    }

    private void sampleSelected(){
        rotateRightButton.setEnabled(true);
        rotateLeftButton.setEnabled(true);
        int degrees = (int) (currentSampleInformations.get(currentSampleIndex).rotation * 180 / java.lang.Math.PI);
        rotationLabel.setText("Rotation : "
                + degrees
                +"°");
        rotationSlider.setValue(degrees);

    }

    @Action
    public void rotateLeftAction() {
        if(currentSampleIndex >= 0){
            currentSampleInformations.get(currentSampleIndex).rotation += java.lang.Math.PI/180;
            if(currentSampleInformations.get(currentSampleIndex).rotation>=2*java.lang.Math.PI)
                currentSampleInformations.get(currentSampleIndex).rotation = 0;
            rotationSlider.setValue( (int) (
                    currentSampleInformations.get(currentSampleIndex).rotation*180/java.lang.Math.PI));
            rotationLabel.setText(
                    "Rotation : "
                    + (int) (currentSampleInformations.get(currentSampleIndex).rotation * 180 / java.lang.Math.PI)
                    +"°");
            currentSampleInformations.get(currentSampleIndex).updatePolygon();
            sampleDrawPanel.repaint();
            imageDrawPanel.repaint();
        }
    }

    @Action
    public void rotateRightAction() {
        if(currentSampleIndex >= 0){
            currentSampleInformations.get(currentSampleIndex).rotation -= java.lang.Math.PI/180;
            if(currentSampleInformations.get(currentSampleIndex).rotation<=0)
                currentSampleInformations.get(currentSampleIndex).rotation = 359.0/360.0*2.0*java.lang.Math.PI;
            rotationSlider.setValue( (int) (
                    currentSampleInformations.get(currentSampleIndex).rotation*180/java.lang.Math.PI));
            rotationLabel.setText(
                    "Rotation : "
                    + (int) (currentSampleInformations.get(currentSampleIndex).rotation * 180 / java.lang.Math.PI)
                    +"°");
            currentSampleInformations.get(currentSampleIndex).updatePolygon();
            sampleDrawPanel.repaint();
            imageDrawPanel.repaint();
        }
    }

    private void emptyDirectory(File directory){
        File[] children = directory.listFiles();
        for(int i = children.length - 1 ; i >= 0 ; i--){
            children[i].delete();
        }
    }

    private class resumeableSaveWorker extends SwingWorker {

        private Runnable updateProgressBar = new Runnable() {

            public void run() {
                progressBar.setValue(savingAll_imageIndex);
                mainPanel.getParent().repaint();
            }
        };

        private void wipeDirectory(File machin) {
            if (machin != null && machin.exists() && machin.isDirectory()) {
                emptyDirectory(machin);
                machin.delete();
            }
        }

        public Object doInBackground() {
            while (savingAll_imageIndex < 0) {
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.FRONT.toString().toLowerCase())));
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.NOTAFACE.toString().toLowerCase())));
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.HALFLEFTPROFILE.toString().toLowerCase())));
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.HALFRIGHTPROFILE.toString().toLowerCase())));
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.FULLLEFTPROFILE.toString().toLowerCase())));
                wipeDirectory(new File(
                        currentImageFile.getParent().concat(
                        "" + File.separatorChar + Facing.FULLRIGHTPROFILE.toString().toLowerCase())));
                savingAll_imageIndex = 0;
                open(currentImageFiles[savingAll_imageIndex]);
                //valid since "saveAllAction" cannot be clicked unless at least an image
                //is selected, hence, currentImageFiles is nonempty.
            }
            do {

                if (currentMetaFile != null && currentMetaFile.exists()) {
                    saveAction();
                }
                savingAll_imageIndex++;
                SwingUtilities.invokeLater(updateProgressBar);
                if(savingAll_imageIndex < currentImageFiles.length)
                    open(currentImageFiles[savingAll_imageIndex]);
                else
                    break;
            } while(true);
            return null;
        }
        @Override
        public void done() {
            if (savingAll_imageIndex == currentImageFiles.length) {
                savingAll = false;
                savingAll_imageIndex = -1;
                statusMessageLabel.setText("");
                enableInterface();
                progressBar.setVisible(false);
            } else {
                new resumeableSaveWorker().execute();
            }
        }
    }

    @Action
    public void saveAllAction() {
        if(fileOpened){
            progressBar.setMinimum(0);
            progressBar.setMaximum(currentImageFiles.length);
            progressBar.setValue(0);
            progressBar.setEnabled(true);
            progressBar.repaint();
            progressBar.setIndeterminate(true);
            progressBar.setVisible(true);

            savingAll = true;
            savingAll_imageIndex = -1;

            statusMessageLabel.setText("Saving all...");

            disableInterface();

            SwingWorker saveWorker = new resumeableSaveWorker();
            
            saveWorker.execute();
        }

    }

    @Action
    public void NoFaceAtAllSelected() {
        if (this.fileOpened) {
            if (!userSaidNoFaces) {

                if ((currentSampleInformations != null) && (currentSampleInformations.size() > 0)) {
                    if (JOptionPane.CANCEL_OPTION == JOptionPane.showConfirmDialog(null,
                            "Using this option will erase the current samples choosen."
                            + "Do you want to continue?", "Are you sure ?", JOptionPane.OK_CANCEL_OPTION)) {
                        this.noFaceAtAllButton.setSelected(false);
                        this.noFaceAtAllButton.repaint();
                        return;
                    }
                }
                currentSampleInformations = null;
                deselectSample();
                this.getFrame().repaint();
            } else {
                this.currentSampleInformations = new ArrayList<SampleInformation>();
            }
            userSaidNoFaces = !userSaidNoFaces;
        }
    }

    private class openSeveralNextWorker extends SwingWorker {
        public Object doInBackground() {
            for(int i = Integer.parseInt(multiplierSpinner.getValue().toString()) - 1 ; i >= 0 ; i--)
                openNextImageAction();
            return null;}
        @Override
        public void done() {enableInterface();}}

    @Action
    public void severalNextOpenAction() {
        disableInterface();
        new openSeveralNextWorker().execute();
    }

    private class openSeveralPreviousWorker extends SwingWorker {
        public Object doInBackground() {
            for (int i = Integer.parseInt(multiplierSpinner.getValue().toString()) - 1; i >= 0; i--)
                openPreviousImageAction();
            return null;}
        @Override
        public void done() {enableInterface();}}

    @Action
    public void severalPreviousOpenAction() {
        disableInterface();
        new openSeveralPreviousWorker().execute();
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JToggleButton FLjTButton;
    private javax.swing.JToggleButton FRjTButton;
    private javax.swing.JToggleButton FjTButton;
    private javax.swing.JToggleButton HLjTButton;
    private javax.swing.JToggleButton HRjTButton;
    private javax.swing.JCheckBox carryOnSampleInformationCheckBox;
    private javax.swing.JPanel imageDrawPanel;
    private javax.swing.JPanel imagePanel;
    private javax.swing.JPanel imageSelectPanel;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JLabel lowerPaddingLabel1;
    private javax.swing.JLabel lowerPaddingLabel2;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JSpinner multiplierSpinner;
    private javax.swing.JLabel multiplierSpinnerLabel;
    private javax.swing.JPanel nPanel;
    private javax.swing.JButton nextImageButton;
    private javax.swing.JToggleButton noFaceAtAllButton;
    private javax.swing.JToggleButton notAFaceTButton;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JMenuItem openNextMenuItem;
    private javax.swing.JLabel paddingLabel1;
    private javax.swing.JLabel paddingLabel2;
    private javax.swing.JButton previousImageButton;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JButton rotateLeftButton;
    private javax.swing.JButton rotateRightButton;
    private javax.swing.JLabel rotationLabel;
    private javax.swing.JSlider rotationSlider;
    private javax.swing.JPanel sampleDrawPanel;
    private javax.swing.JPanel samplePanel;
    private javax.swing.JPanel sampleRotationPanel;
    private javax.swing.JMenuItem saveAllMenuItem;
    private javax.swing.JButton saveImageButton;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JButton severalNextImageButton;
    private javax.swing.JButton severalPreviousImageButton;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
}
